package com.jk.controller;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.jk.model.*;
import com.jk.service.LXCService;
import com.jk.utils.OSSClientUtil;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;

@Controller
@RequestMapping("product")
public class LXCController {

    @Reference(check = false,timeout = 100000)
    private LXCService lxcService;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 获取登录账号
     * @param session
     * @return
     */
    @RequestMapping("checkLogin")
    @ResponseBody
    public Map checkLogin(HttpSession session){
        HashMap<String, Object> result = new HashMap<>();
        UserBean userBean = (UserBean) session.getAttribute(session.getId());
        if (userBean==null){
            result.put("code",1);
            result.put("msg","未登陆");
            return result;
        }
        result.put("code",2);
        result.put("msg","已登陆");
        result.put("userName",userBean.getUserAccount());
        return result;
    }

    /**
     * 商城导航
     * @return
     */
    @RequestMapping("findProductTree")
    @ResponseBody
    public List<ProductTree> findProductTree(){
        return lxcService.findProductTree();
    }

    /**
     * 新增商品
     * @param productBean
     * @return
     */
    @RequestMapping("addProduct")
    @ResponseBody
    public Boolean addProudct(ProductBean productBean,HttpSession session){
        try {
            UserBean attribute = (UserBean) session.getAttribute(session.getId());
            Integer storeId = attribute.getStoreId();
            productBean.setStoreId(storeId);
            lxcService.addProudct(productBean,storeId);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 商品分页查询
     * @param page
     * @param rows
     * @param productBean
     * @return
     */
    @RequestMapping("findProductList")
    @ResponseBody
    public Map findProduct(Integer page, Integer rows, ProductBean productBean,HttpSession session){
        UserBean attribute = (UserBean) session.getAttribute(session.getId());
        Integer storeId = attribute.getStoreId();
        return lxcService.findProductList(page,rows,productBean,storeId);
    }

    /**
     * 商品上下架
     * @param productId
     * @param falg
     * @return
     */
    @RequestMapping("productState")
    @ResponseBody
    public Boolean productState(Integer productId,Integer falg){
        try {
            if(falg==1){
                //删除Es中的数据
                elasticsearchTemplate.delete(ProductBean.class,productId.toString());
            }
            lxcService.productState(productId,falg);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 条查：加载类型
     * @return
     */
    @RequestMapping("findProductType")
    @ResponseBody
    public List<ProductTypeBean> findProductType(){
        return lxcService.findProductType();
    }

    /**
     * 删除商品
     * @param productId
     * @return
     */
    @RequestMapping("delProduct")
    @ResponseBody
    public Boolean delProduct(Integer productId){
        try {
            //删除数据库中的数据
            lxcService.delProduct(productId);
            //删除Es中的数据
            elasticsearchTemplate.delete(ProductBean.class,productId.toString());
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 库存商品列表
     * @param page
     * @param rows
     * @return
     */
    @RequestMapping("findProductStock")
    @ResponseBody
    public Map findProductStock(Integer page, Integer rows,ProductBean productBean,HttpSession session){
        UserBean attribute = (UserBean) session.getAttribute(session.getId());
        Integer storeId = attribute.getStoreId();
        return lxcService.findProductStock(page,rows,productBean,storeId);
    }

    /**
     * 库存：商品批量上架
     * @param ids
     * @return
     */
    @RequestMapping("productManyStock")
    @ResponseBody
    public Boolean productManyStock(Integer[] ids){
        try {
            lxcService.productManyStock(ids);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 店铺：出售中的商品
     * @param page
     * @param rows
     * @param productBean
     * @return
     */
    @RequestMapping("findStoreProductList")
    @ResponseBody
    public Map findStoreProductList(Integer page, Integer rows,ProductBean productBean,HttpSession session){
        UserBean attribute = (UserBean) session.getAttribute(session.getId());
        Integer storeId = attribute.getStoreId();
        return lxcService.findStoreProductList(page,rows,productBean,storeId);
    }

    /**
     * 店铺：下架的商品
     * @param page
     * @param rows
     * @param productBean
     * @return
     */
    @RequestMapping("findStoreDownProduct")
    @ResponseBody
    public Map findStoreDownProduct(Integer page, Integer rows,ProductBean productBean,HttpSession session){
        UserBean attribute = (UserBean) session.getAttribute(session.getId());
        Integer storeId = attribute.getStoreId();
        return lxcService.findStoreDownProduct(page,rows,productBean,storeId);
    }

    /**
     * 审核中的商品
     * @param page
     * @param rows
     * @param productBean
     * @return
     */
    @RequestMapping("findAuditProduct")
    @ResponseBody
    public Map findAuditProduct(Integer page, Integer rows,ProductBean productBean,HttpSession session){
        UserBean attribute = (UserBean) session.getAttribute(session.getId());
        Integer storeId = attribute.getStoreId();
        return lxcService.findAuditProduct(page,rows,productBean,storeId);
    }

    /**
     * 图片上传
     * @param imgfile
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping("upload")
    @ResponseBody
    public Map upload(MultipartFile imgfile, HttpServletRequest request) throws IOException {
        OSSClientUtil ossClient = new OSSClientUtil();
        String name = ossClient.uploadImg2Oss(imgfile);
        String fileUpload = ossClient.getImgUrl(name);
        HashMap<String, Object> result = new HashMap<>();
        result.put("img", fileUpload);
        return result;
    }

    /**
     * 店铺查询
     * @return
     */
    @RequestMapping("findStore")
    @ResponseBody
    public List<StoreBean> findStore(){
        return lxcService.findStore();
    }


    /**
     * 日志查询
     * @param page
     * @param rows
     * @return
     */
    @RequestMapping("findLogList")
    @ResponseBody
    public Map findLogList(Integer page, Integer rows){
        //构建总返回
        HashMap<String, Object> result = new HashMap<>();
        //查询方法
        Query query = new Query();
        //查询count
        long count = mongoTemplate.count(query , LogBean.class);
        query.skip((page-1)*rows);
        query.limit(rows);
        //查询list
        List<LogBean> find = mongoTemplate.find(query, LogBean.class);
        result.put("total", count);
        result.put("rows", find);
        return result;
    }


    /**
     * 登录
     * @return
     */
    @RequestMapping("login")
    @ResponseBody
    public Map login(UserBean userBean, int code,HttpSession session ){
        HashMap<String, Object> resyIt = new HashMap<>();
        //获取验证码
        Object attribute = session.getAttribute("imgcode");
        if(attribute==null) {
            resyIt.put("code", 1);
            resyIt.put("msg", "验证码错误");
            return resyIt;
        }
        //判断session中的验证码和输入的验证码是否一致
        int imgCode = Integer.parseInt(attribute.toString());
        if(imgCode!=code) {
            resyIt.put("code", 1);
            resyIt.put("msg", "验证码错误");
            return resyIt;
        }
        UserBean userInfo = lxcService.findUserInfoByAccount(userBean.getUserAccount());
        if (userInfo == null) {
            resyIt.put("code", 2);
            resyIt.put("msg", "账号密码错误");
            return resyIt;
        }
        if (!userInfo.getUserPassword().equals(userBean.getUserPassword())) {
            resyIt.put("code", 3);
            resyIt.put("msg", "账号密码错误");
            return resyIt;
        }if(userInfo.getUserRole() !=2){
            resyIt.put("code", 4);
            resyIt.put("msg", "请登录商家账号");
            return resyIt;
        }
        resyIt.put("code", 0);
        resyIt.put("msg", "登陆成功");
        session.setAttribute(session.getId(),userInfo);
        return resyIt;
    }

    /**
     * 索引
     * @return
     */
    @RequestMapping("cratetIndex")
    @ResponseBody
    public Boolean cratetIndex (){
        //将查出来的数据存入elastic
        boolean exists = elasticsearchTemplate.indexExists(ProductBean.class);
        if (!exists) {
            elasticsearchTemplate.createIndex(ProductBean.class);
        }
        List<ProductBean> products = lxcService.findProduct();
        ArrayList<IndexQuery> indexQueries = new ArrayList<>();
        for (ProductBean product : products) {
            IndexQuery indexQuery = new IndexQueryBuilder()
                    .withId(product.getId().toString())
                    .withObject(product)
                    .build();
            indexQueries.add(indexQuery);
        }
        elasticsearchTemplate.bulkIndex(indexQueries);
        return true;
    }

    /**
     * 商品分页列表 高亮
     *
     * @param page
     * @param rows
     * @param asc
     * @param startPrice
     * @param endPrice
     * @param productBean
     * @return
     */
    @RequestMapping("findGoodsList")
    @ResponseBody
    public Map findGoodsList(Integer page, Integer rows, Integer asc,Double startPrice,Double endPrice ,ProductBean productBean) {
        //总返回
        HashMap<Object, Object> result = new HashMap<>();
        //注意开始是从0开始，有点类似sql中的方法limit 的查询
        PageRequest pageable = PageRequest.of(page - 1, rows);
        //高亮
        HighlightBuilder.Field highlightBuilder = new HighlightBuilder.Field("productName").preTags("<em style='color:red'>").postTags("</em>");
        //搜索条件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        if (!StringUtils.isEmpty(productBean.getProductName())){
            boolQueryBuilder.must(matchQuery("productName",productBean.getProductName()));
        }
        if (startPrice != null){
            boolQueryBuilder.must(rangeQuery("productPrice").gte(startPrice));
        }
        if (endPrice != null){
            boolQueryBuilder.must(rangeQuery("productPrice").lte(endPrice));
        }
        NativeSearchQuery searchQueryBuilder = nativeSearchQueryBuilder.withQuery(boolQueryBuilder)
                .withHighlightFields(highlightBuilder)
                .withPageable(pageable)
                .build();
        //价格排序
        if (asc!=null && asc !=-1){
            Sort sort1 = new Sort(Sort.Direction.ASC,"productPrice");
            Sort sort2 = new Sort(Sort.Direction.DESC,"productPrice");
            if (asc==1) {
                searchQueryBuilder.addSort(sort1);
            }
            if (asc==2) {
                searchQueryBuilder.addSort(sort2);
            }
        }
        // long count = elasticsearchTemplate.count(searchQueryBuilder,GoodsBean.class);
        // List<GoodsBean> goodsBeans = elasticsearchTemplate.queryForList(searchQueryBuilder, GoodsBean.class);
        AggregatedPage<ProductBean> goodsBeans = elasticsearchTemplate.queryForPage(searchQueryBuilder, ProductBean.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                SearchHits hits = searchResponse.getHits();
                List<T> chunk = new ArrayList<>();
                for (SearchHit hit : hits) {
                    Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    chunk.add((T)createBean(sourceAsMap,highlightFields));
                }
                AggregatedPage<T> result=new AggregatedPageImpl<T>(chunk,pageable,searchResponse.getHits().getTotalHits());
                return result;
            }
        });
        //获取总共多少条数据
        long totalElements = goodsBeans.getTotalElements();
        result.put("total",totalElements);
        //获取返回内容
        List<ProductBean> content = goodsBeans.getContent();
        result.put("rows",content);
        return result;
    }

    private ProductBean createBean(Map<String, Object> sourceAsMap,Map<String, HighlightField> highlightFields){
        HighlightField productName = highlightFields.get("productName");
        String title = "";
        if (productName != null){
            Text[] fragments = productName.getFragments();
            for (Text fragment : fragments) {
                title += fragment.toString();
            }
        }
        sourceAsMap.put("productName",highlightFields.size() > 0 ? title: sourceAsMap.get("productName"));
        String jsonString = JSON.toJSONString(sourceAsMap);
        ProductBean productBean = JSON.parseObject(jsonString, ProductBean.class);
        return productBean;
    }

    @RequestMapping("findStock")
    @ResponseBody
    public List<StockBean> findStock(){
        return lxcService.findStock();
    }


}
